package com.wedu.modules.dss.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.wedu.common.utils.PageUtils;
import com.wedu.common.utils.Query;
import com.wedu.modules.dss.dao.DeviceDao;
import com.wedu.modules.dss.dao.OperationStatusDao;
import com.wedu.modules.dss.dao.UsageEfficiencyDao;
import com.wedu.modules.dss.entity.DeviceEntity;
import com.wedu.modules.dss.entity.OperationStatusEntity;
import com.wedu.modules.dss.entity.UsageEfficiencyEntity;
import com.wedu.modules.dss.entity.Vo.UsageEfficiencyEntityVo;
import com.wedu.modules.dss.service.DssUsageEfficiencyService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service("DssUsageEfficiencyService")
public class UsageEfficiencyImpl extends MPJBaseServiceImpl<UsageEfficiencyDao, UsageEfficiencyEntity> implements DssUsageEfficiencyService {
    @Autowired
    private OperationStatusDao operationStatusDao;
    @Autowired
    private UsageEfficiencyDao usageEfficiencyDao;
    @Autowired
    private DeviceDao deviceDao;

    @Override
    public PageUtils queryUsageEfficiency(Map<String, Object> params) {
        String devicename = (String) params.get("name");
        String deviceId = (String) params.get("deviceId");
        MPJLambdaWrapper<UsageEfficiencyEntity> wrapper = new MPJLambdaWrapper<>();
        wrapper.select(/*DeviceEntity::getId,*/DeviceEntity::getDeviceName,DeviceEntity::getDeviceId)
                .select(UsageEfficiencyEntity::getDeviceId,UsageEfficiencyEntity::getEfficiency, UsageEfficiencyEntity::getDate)
                .eq(DeviceEntity::getDeleted,0)
                .leftJoin(DeviceEntity.class, DeviceEntity::getId, UsageEfficiencyEntity::getDeviceId)
                .like(StringUtils.isNotBlank(devicename), DeviceEntity::getDeviceName, devicename)
                .like(StringUtils.isNotBlank(deviceId), DeviceEntity::getDeviceId, deviceId)
                .orderByDesc(UsageEfficiencyEntity::getDate);
        if (params.containsKey("startTime") && params.containsKey("endTime")) {
            long startTime = Long.parseLong(params.get("startTime").toString());
            long endTime = Long.parseLong(params.get("endTime").toString());
            wrapper.between(UsageEfficiencyEntity::getDate, new Date(startTime), new Date(endTime));
        }
        dailyTask();
        calculateUsageEfficiency();
//        IPage<UsageEfficiencyEntityVo> page = usageEfficiencyDao.selectJoinPage(
//                new Query<UsageEfficiencyEntityVo>().getPage(params),
//                UsageEfficiencyEntityVo.class,
//                wrapper
//        );
        List<UsageEfficiencyEntityVo> usageEfficiencyEntityVoList = usageEfficiencyDao.selectJoinList(UsageEfficiencyEntityVo.class, wrapper);
        IPage<UsageEfficiencyEntity> page = this.page(new Query<UsageEfficiencyEntity>().getPage(params));
        int current = (int) page.getCurrent();
        int size = (int) page.getSize();
        int start = (current - 1) * size;
        int end = Math.min(start + size, usageEfficiencyEntityVoList.size());
        List<UsageEfficiencyEntityVo> paginatedList = usageEfficiencyEntityVoList.subList(start, end);
        IPage<UsageEfficiencyEntityVo> usageEfficiencyEntityVoIPage = new Page<>();
        usageEfficiencyEntityVoIPage.setTotal(usageEfficiencyEntityVoList.size());
        usageEfficiencyEntityVoIPage.setSize(size);
        usageEfficiencyEntityVoIPage.setPages(page.getPages());
        usageEfficiencyEntityVoIPage.setRecords(paginatedList);
        usageEfficiencyEntityVoIPage.setCurrent(current);
        return new PageUtils(usageEfficiencyEntityVoIPage);
    }

    //从dss_usage_efficiency表中查询出所有设备的日期，并返回对应设备的日期和deviceId，从dss_operation_status根据deviceId
    //在dss_operation_status中根据id查询出在该日期的红灯(-1)时长，绿灯(1)时长，黄灯(0)时长,计算该日期的使用效率绿灯时长/(绿灯时长+黄灯时长+红灯时长)
    //如果dss_operation_status的结束时间为空就用当前电脑时间进行当做结束时间并及时更新，如果出现好几天的等状态没有改变，则当天的灯时长，全天都是该灯时长，
    /**
     * 计算使用每个日期的使用效率
     */
    private void calculateUsageEfficiency() {
        LambdaQueryWrapper<UsageEfficiencyEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(UsageEfficiencyEntity::getDeviceId, UsageEfficiencyEntity::getDate,UsageEfficiencyEntity::getId);

        List<UsageEfficiencyEntity> efficiencyEntities = usageEfficiencyDao.selectList(wrapper);
        for (UsageEfficiencyEntity efficiencyEntity : efficiencyEntities) {
            Date date = efficiencyEntity.getDate();
            Long deviceId = efficiencyEntity.getDeviceId();
            long[] lightDurations = calculateLightDurations(deviceId, date);
            long redDuration = lightDurations[0];
            long greenDuration = lightDurations[1];
            long yellowDuration = lightDurations[2];
            float efficiency = 0f;
            if (greenDuration + yellowDuration + redDuration > 0) {
                efficiency = (float) greenDuration / (greenDuration + yellowDuration + redDuration);
            }
            efficiencyEntity.setEfficiency(efficiency);
            usageEfficiencyDao.updateById(efficiencyEntity);
        }
    }

    /**
     * 计算指定日期的设备的灯时长
     *
     * @param deviceId 设备ID
     * @param date     日期
     * @return [红灯时长，绿灯时长，黄灯时长]
     */
    private long[] calculateLightDurations(Long deviceId, Date date) {
        long redDuration = 0;
        long greenDuration = 0;
        long yellowDuration = 0;
        // 获取指定日期的开始时间和结束时间
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startOfDay = cal.getTime();

        cal.add(Calendar.DAY_OF_YEAR, 1);
        Date endOfDay = cal.getTime();

        // 查询可能与指定日期有交集的操作状态记录
        LambdaQueryWrapper<OperationStatusEntity> statusWrapper = new LambdaQueryWrapper<>();
        statusWrapper.eq(OperationStatusEntity::getDeviceId, deviceId)
                .and(w -> {
                    // 开始时间早于指定日期的结束时间
                    w.lt(OperationStatusEntity::getLightStartTime, endOfDay);
                    // 结束时间晚于指定日期的开始时间 或者 结束时间为 null
                    w.and(ww -> ww.gt(OperationStatusEntity::getLightEndTime, startOfDay)
                            .or().isNull(OperationStatusEntity::getLightEndTime));
                });
        List<OperationStatusEntity> statusEntities = operationStatusDao.selectList(statusWrapper);

        // 处理操作状态记录
        for (OperationStatusEntity statusEntity : statusEntities) {
            Date startTime = statusEntity.getLightStartTime();
            Date endTime = statusEntity.getLightEndTime();
            if (endTime == null) {
                endTime = new Date();
            }

            // 计算与指定日期的交集时长
            long start = Math.max(startTime.getTime(), startOfDay.getTime());
            long end = Math.min(endTime.getTime(), endOfDay.getTime());
            long duration = end - start;

            int status = statusEntity.getLightStatus();
            switch (status) {
                case -1:
                    redDuration += duration;
                    break;
                case 1:
                    greenDuration += duration;
                    break;
                case 0:
                    yellowDuration += duration;
                    break;
            }
        }


        return new long[]{redDuration, greenDuration, yellowDuration};
    }

    @Scheduled(cron = "0 0 0 * * ?")
    public void dailyTask() {
        // 获取所有设备的 deviceId 和 startUseTime
        LambdaQueryWrapper<DeviceEntity> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.select(DeviceEntity::getId, DeviceEntity::getStartUseTime);
        List<DeviceEntity> deviceEntities = deviceDao.selectList(deviceWrapper);

        // 获取当前日期，并将时间部分置为 0
        Calendar currentCal = Calendar.getInstance();
        currentCal.set(Calendar.HOUR_OF_DAY, 0);
        currentCal.set(Calendar.MINUTE, 0);
        currentCal.set(Calendar.SECOND, 0);
        currentCal.set(Calendar.MILLISECOND, 0);
        Date currentDate = currentCal.getTime();

        for (DeviceEntity deviceEntity : deviceEntities) {
            Long deviceId = deviceEntity.getId();
            Date startUseTime = deviceEntity.getStartUseTime();
            if (startUseTime != null) {
                // 将 startUseTime 的时间部分置为 0
                Calendar startCal = Calendar.getInstance();
                startCal.setTime(startUseTime);
                startCal.set(Calendar.HOUR_OF_DAY, 0);
                startCal.set(Calendar.MINUTE, 0);
                startCal.set(Calendar.SECOND, 0);
                startCal.set(Calendar.MILLISECOND, 0);
                startUseTime = startCal.getTime();

                // 检查该设备的最早使用效率记录
                LambdaQueryWrapper<UsageEfficiencyEntity> earliestWrapper = new LambdaQueryWrapper<>();
                earliestWrapper.eq(UsageEfficiencyEntity::getDeviceId, deviceId)
                        .orderByAsc(UsageEfficiencyEntity::getDate)
                        .last("LIMIT 1");
                UsageEfficiencyEntity earliestRecord = usageEfficiencyDao.selectOne(earliestWrapper);

                Date earliestDate = earliestRecord != null ? earliestRecord.getDate() : startUseTime;
                // 如果 startUseTime 比数据库中的最早日期还早，以 startUseTime 为准
                if (startUseTime.before(earliestDate)) {
                    earliestDate = startUseTime;
                }

                // 计算从最早日期到当前日期的天数差
                long daysBetween = calculateDaysBetween(earliestDate, currentDate);

                for (int i = 0; i <= daysBetween; i++) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(earliestDate);
                    cal.add(Calendar.DAY_OF_YEAR, i);
                    Date newDate = cal.getTime();

                    // 检查该日期的记录是否已经存在
                    if (!isRecordExists(deviceId, newDate)) {
                        UsageEfficiencyEntity usageEfficiencyEntity = new UsageEfficiencyEntity();
                        usageEfficiencyEntity.setDeviceId(deviceId);
                        // 这里假设数据库中日期字段是 Date 类型，使用 Timestamp 可以兼容 datetime 类型
                        usageEfficiencyEntity.setDate(new Timestamp(newDate.getTime()));
                        usageEfficiencyEntity.setEfficiency(0f); // 可根据实际情况设置效率值
                        usageEfficiencyDao.insert(usageEfficiencyEntity);
                    }
                }
            }
        }
    }

    /**
     * 计算两个日期之间的天数差
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 天数差
     */
    private long calculateDaysBetween(Date startDate, Date endDate) {
        long diffInMillis = endDate.getTime() - startDate.getTime();
        return diffInMillis / (24 * 60 * 60 * 1000);
    }

    /**
     * 检查指定日期的记录是否已经存在
     * @param deviceId 设备 ID
     * @param date 日期
     * @return 是否存在记录
     */
    private boolean isRecordExists(Long deviceId, Date date) {
        LambdaQueryWrapper<UsageEfficiencyEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UsageEfficiencyEntity::getDeviceId, deviceId)
                .eq(UsageEfficiencyEntity::getDate, new Timestamp(date.getTime()));
        return usageEfficiencyDao.selectCount(wrapper) > 0;
    }


}